package com.zkyc.framework.schedulejob.task;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jcraft.jsch.ChannelSftp;
import com.zkyc.framework.common.pojo.ClientMsg;
import com.zkyc.framework.common.pojo.FileVerification;
import com.zkyc.framework.common.vo.ResultVO;
import com.zkyc.framework.schedulejob.client.ClientMsgClient;
import com.zkyc.framework.schedulejob.client.FileVerificationClient;
import com.zkyc.framework.schedulejob.utils.JschUtils;
import javafx.util.Pair;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.io.*;
import java.security.MessageDigest;
import java.util.*;



@Slf4j
@Component
public class TamperDenfenceTask {

    @Autowired
    private FileVerificationClient fileVerificationClient;
    @Autowired
    private ClientMsgClient clientMsgClient;
    @Autowired
    private RestTemplate restTemplate;

    @Value("${dingding.url}")
    private String url;
    /**
     * 每四小时同步一次
     */
    @Scheduled(cron = "*/5 * * * * ?")
    public void process() {
        ResultVO<Page<ClientMsg>> resultVO1 = (ResultVO<Page<ClientMsg>>)clientMsgClient.list(null,1,10);

        List<ClientMsg> clientMsgs = resultTransformPage(resultVO1, ClientMsg.class);
        for (ClientMsg clientMsg : clientMsgs) {

            JschUtils jschUtils = null;
            FileVerification fileMsg = null;
            try {
                jschUtils = new JschUtils(clientMsg.getIp(), clientMsg.getUsername(), clientMsg.getPassword());
                jschUtils.connectSftp();
                ChannelSftp channelSftp = jschUtils.getChannelSftp();
                ResultVO<?> resultVO2 = fileVerificationClient.list(clientMsg.getId(), "", -1, -1);
                List<FileVerification> fs = resultTransformPage(resultVO2, FileVerification.class);
                //库中不存在防篡改信息
                if (CollectionUtils.isEmpty(fs)) {
                    List<Pair<String, String>> filePaths = new ArrayList<>();
                    jschUtils.getFileNames(clientMsg.getPath(), filePaths);

                    fs = new ArrayList<>();

                    for (Pair<String, String> filePath : filePaths) {
                        String path = filePath.getKey() + "/" + filePath.getValue();
                        FileVerification fileVerification = new FileVerification();
                        fs.add(fileVerification);
                        fileVerification.setFileName(filePath.getValue());
                        InputStream inputStream = channelSftp.get(path);
                        fileVerification.setMd5Code(md5Encrypt(inputStream));
                        fileVerification.setPath(path);
                        fileVerification.setCid(clientMsg.getId());
                    }

                    ResultVO resultVO3 = fileVerificationClient.saveBatch(fs);
                    boolean result = resultTransform("success", resultVO3, Boolean.class);
                    sendMsg("新的防篡改信息入库" + (result ? "成功" : "失败") + "!" + "ip:" + clientMsg.getIp() + ",目标路径:"+ clientMsg.getPath());
                    continue;
                }

                for (FileVerification fileVerification : fs) {
                    fileMsg = fileVerification;
                    InputStream inputStream = channelSftp.get(fileVerification.getPath());
                    if (Objects.isNull(inputStream)) {
                        sendMsg("文件获取失败, 文件可能被篡改删除，请去服务器确认！文件名:" + fileVerification.getFileName() + ",路径:"+ fileVerification.getPath());
                        continue;
                    }
                    String md5 = md5Encrypt(inputStream);
                    if (!StringUtils.equals(md5, fileVerification.getMd5Code())) {
                        //向钉钉发送信息
                        sendMsg("文件md5校验失败, 文件可能被篡改，请去服务器确认！文件名:" + fileVerification.getFileName() + ",路径:"+ fileVerification.getPath());
                        continue;
                    }
                }
            }catch (Exception e) {
                e.printStackTrace();
                sendMsg("文件md5校验失败, 文件可能被篡改，请去服务器确认！文件名:" + fileMsg.getFileName() + ",路径:"+ fileMsg.getPath());
            }finally {
                if (Objects.nonNull(jschUtils)) jschUtils.disconnect();
            }

        }
    }

    private <T> T resultTransform(String resultParam, ResultVO resultVO, Class<T> clazz) {
        JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(resultVO));
        T result = JSONObject.parseObject(jsonObject.getString(resultParam), clazz);
        return result;
    }

    private <T> List<T> resultTransformPage(ResultVO resultVO, Class<T> clazz) {
        List<JSONObject> list = resultTransform("data", resultVO, Page.class).getRecords();
        List<T> result = new ArrayList<>();
        list.forEach(b -> result.add(JSONObject.parseObject(b.toJSONString(), clazz)));
        return result;
    }

    private String md5Encrypt(InputStream inputStream) throws Exception {

        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] bytes = new byte[10240];
        int len;
        while ((len = inputStream.read(bytes)) != -1) {
            md.update(bytes, 0, len);
        }
        //加密结果
        inputStream.close();
        String md5 = Hex.encodeHexString(md.digest());
        //System.out.println("加密结果：" + md5);
        return md5;
    }


    private void sendMsg(String msg) {

        Map<String, Object> map = new HashMap<>();
        Map<String, Object> content = new HashMap<>();
        map.put("msgtype", "text");
        map.put("text", content);
        //map.put("isAtAll", true);

        content.put("content", "防篡改提醒: " + msg);
        String s = restTemplate.postForObject(url, map, String.class);
        //System.out.println(s);
    }

    public static void main(String[] args) throws Exception {
//        File file = new File("/Users/baibing/Desktop/pythondemo/p.py");
//        FileInputStream inputStream = null;
//        FileOutputStream outputStream = null;
//        MessageDigest md = MessageDigest.getInstance("MD5");
//        inputStream = new FileInputStream(file);
//        byte[] bytes = new byte[10240];
//        int len;
//        while ((len = inputStream.read(bytes)) != -1) {
//            md.update(bytes, 0, len);
//        }
//        //加密结果
//        inputStream.close();
//        String md5 = Hex.encodeHexString(md.digest());
//        System.out.println("加密结果：" + md5);
        //sendMsg();
    }

}
